/*
 * Copyright (c) 2018-2999 湖南洛云网络科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 */

package com.yami.shop.groupbuy.comment.service.impl;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.dto.OrderRefundDto;
import com.yami.shop.bean.enums.*;
import com.yami.shop.bean.model.Order;
import com.yami.shop.bean.model.OrderRefund;
import com.yami.shop.bean.model.Product;
import com.yami.shop.groupbuy.comment.api.dto.ApiGroupTeamDto;
import com.yami.shop.groupbuy.comment.api.dto.ApiJoinGroupTeamDto;
import com.yami.shop.groupbuy.comment.dao.GroupActivityMapper;
import com.yami.shop.groupbuy.comment.dao.GroupOrderMapper;
import com.yami.shop.groupbuy.comment.dao.GroupTeamMapper;
import com.yami.shop.groupbuy.comment.dto.GroupRefundOrder;
import com.yami.shop.groupbuy.comment.dto.GroupTeamDto;
import com.yami.shop.groupbuy.comment.enums.GroupOrderStatusEnum;
import com.yami.shop.groupbuy.comment.enums.TeamStatusEnum;
import com.yami.shop.groupbuy.comment.model.GroupOrder;
import com.yami.shop.groupbuy.comment.model.GroupProd;
import com.yami.shop.groupbuy.comment.model.GroupTeam;
import com.yami.shop.groupbuy.comment.service.GroupOrderService;
import com.yami.shop.groupbuy.comment.service.GroupProdService;
import com.yami.shop.groupbuy.comment.service.GroupTeamService;
import com.yami.shop.service.NotifyTemplateService;
import com.yami.shop.service.OrderRefundService;
import com.yami.shop.service.OrderService;
import com.yami.shop.service.ProductService;
import lombok.AllArgsConstructor;
import ma.glasnost.orika.MapperFacade;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 拼团团队表
 *
 * @author LGH
 * @date 2019-08-27 17:55:57
 */
@Service
@AllArgsConstructor
public class GroupTeamServiceImpl extends ServiceImpl<GroupTeamMapper, GroupTeam> implements GroupTeamService {

    private final GroupTeamMapper groupTeamMapper;
    private final GroupActivityMapper groupActivityMapper;
    private final GroupOrderMapper groupOrderMapper;
    private final GroupProdService groupProdService;
    private final GroupOrderService groupOrderService;
    private final ProductService productService;
    private final OrderRefundService orderRefundService;
    private final NotifyTemplateService notifyTemplateService;
    private final OrderService orderService;
    private final Snowflake snowflake;
    private final MapperFacade mapperFacade;

    /**
     * 获取分页列表
     */
    @Override
    public IPage<GroupTeamDto> getPage(Page page, GroupTeamDto groupTeamDto) {
        return groupTeamMapper.getPage(page, groupTeamDto);
    }

    /**
     * 可加入的团列表
     *
     * @param groupActivityId 拼团活动ID
     * @param prodId          商品ID
     * @param showSize          显示数量（默认10）
     * @return 团列表（最近n个）
     */
    @Override
    public List<ApiGroupTeamDto> listJoinGroup(Long groupActivityId, Long prodId, Integer showSize) {
        return groupTeamMapper.listByJoinGroupAndNowDate(groupActivityId, prodId, new Date(), showSize);
    }

    /**
     * 获取拼团单（拼团团队）信息
     *
     * @param groupTeamId 团单ID
     * @return ApiGroupTeamDto对象
     */
    @Override
    public ApiGroupTeamDto getApiGroupTeamDto(Long groupTeamId) {
        return groupTeamMapper.getApiGroupTeamDtoByTeamId(groupTeamId);
    }

    /**
     * 获取参加的拼团团队信息
     *
     * @param groupActivityId 活动ID
     * @param prodId          商品ID
     * @return 拼团团队ID
     */
    @Override
    public ApiJoinGroupTeamDto getJoinGroupTeamHasMaxNum(Long groupActivityId, Long prodId) {
        return groupTeamMapper.getJoinGroupTeamHasMaxNum(groupActivityId, prodId);
    }

    /**
     * 获取活动结束或团单结束未成团的拼团团队
     *
     * @return ApiGroupTeamDto对象
     */
    @Override
    public List<GroupTeam> getNotGroupTeam() {
        return groupTeamMapper.getNotGroupTeamByNowDate(new Date());
    }

    /**
     * 处理活动结束或团单结束未成团的拼团团队
     *
     * @param groupTeam 未成团的拼团团队
     * @return 退款单列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateNotGroupTeam(GroupTeam groupTeam) {
        Date nowDate = new Date();
        // 机器人列表
        List<GroupOrder> robot = new ArrayList<>();
        // 拼团成功的活动商品列表（机器人）
        List<GroupProd> groupProdList = new ArrayList<>();

        // 修改订单状态(拼团中的状态定时任务修改不了及防止待成团订单重新进行支付)
        List<Order> changeStatusOrderList = new ArrayList<>();

        // 需要还原库存的订单
        List<Order> returnStockOrders = new ArrayList<>();

        // 未支付的拼团，不需要进行退款的操作
        if (groupTeam.getStatus().equals(TeamStatusEnum.WAITING_GROUP.value())) {
            groupTeam.setStatus(TeamStatusEnum.FAIL.value());
            // 获取拼团失败要取消的订单
            List<Order> teamOrderList = groupTeamMapper.getOrders(groupTeam.getGroupTeamId(),null);
            if(CollectionUtils.isNotEmpty(teamOrderList)){
                // 需要还原库存的订单
                returnStockOrders.addAll(teamOrderList);
                for (Order order : teamOrderList) {
                    order.setStatus(OrderStatus.CLOSE.value());
                    order.setCancelTime(nowDate);
                    order.setUpdateTime(nowDate);
                    changeStatusOrderList.add(order);
                }
            }
        }

        // 如果未成团，有机器人可以成团，不需要进行退款的操作
        if (groupTeam.getStatus().equals(TeamStatusEnum.IN_GROUP.value()) && groupTeam.getHasRobot() == 1) {
            handleWaitingGroupOrder(nowDate, groupTeam, groupProdList, robot, changeStatusOrderList, returnStockOrders);
        }

        // 如果在拼团中订单且没有模拟成团则需要退款
        if (groupTeam.getStatus().equals(TeamStatusEnum.IN_GROUP.value()) && groupTeam.getHasRobot() == 0) {
            handleRefundGroupOrder(groupTeam, changeStatusOrderList);

        }

        // 更新拼团团队信息
        groupTeam.setUpdateTime(nowDate);
        updateById(groupTeam);

        // 取消订单，还原库存
        if (CollectionUtils.isNotEmpty(returnStockOrders)) {
            orderService.cancelOrders(returnStockOrders);
        }
        // 批量保存机器人
        if (robot.size() > 0) {
            groupOrderService.saveBatch(robot);
        }
        // 批量更新拼团成功的活动商品列表
        if (groupProdList.size() > 0) {
            groupProdService.saveOrUpdateBatch(groupProdList);
        }

        // 更新订单状态
        if (changeStatusOrderList.size() > 0) {
            orderService.saveOrUpdateBatch(changeStatusOrderList);
        }

        // 批量清除商品拼团活动ID
        List<Product> products = groupActivityMapper.getActivityFinishProduct(nowDate);
        for (Product product : products) {
            product.setActivityId(0L);
            product.setProdType(ProdType.PROD_TYPE_NORMAL.value());
        }
        if (products.size() > 0) {
            productService.saveOrUpdateBatch(products);
        }
    }

    @Override
    public List<GroupTeam> getNotGroupTeamsByActivityIdAndGroupProdId(Long groupActivityId, Long groupProdId) {
        return groupTeamMapper.getNotGroupTeamsByActivityIdAndGroupProdId(groupActivityId, groupProdId);
    }

    @Override
    public List<GroupTeam> getNotGroupTeamsByActivityId(Long groupActivityId) {
        return groupTeamMapper.getNotGroupTeamsByActivityId(groupActivityId);
    }

    @Override
    public List<GroupTeam> getNotGroupTeamByProdId(Long prodId) {
        return groupTeamMapper.getNotGroupTeamByProdId(prodId);
    }

    /**
     * 并生成退款单并保存到数据库，且获组装退款dto
     * @param groupRefundOrder 团购退款订单数据
     * @return 团购退款订单列表
     */
    private List<OrderRefundDto> saveRefundOrderAndGetOrderRefundDtoByGroupTeamId(List<GroupRefundOrder> groupRefundOrder) {
        // 退款单列表
        List<OrderRefund> orderRefundList = new ArrayList<>();
        // 退款数据列表
        List<OrderRefundDto> orderRefundDtoList = new ArrayList<>();

        for (GroupRefundOrder refundOrder : groupRefundOrder) {
            // 生成退款单信息
            OrderRefund orderRefund = new OrderRefund();
            orderRefund.setRefundSn(String.valueOf(snowflake.nextId()));
            orderRefund.setShopId(refundOrder.getShopId());
            orderRefund.setUserId(refundOrder.getUserId());
            orderRefund.setOrderId(refundOrder.getOrderId());
            orderRefund.setRefundType(RefundType.ALL.value());
            orderRefund.setRefundAmount(refundOrder.getActualTotal());
            orderRefund.setApplyType(1);
            orderRefund.setIsReceiver(false);
            orderRefund.setBuyerReason(BuyerReasonType.GROUP_FAILED.value()+"");
            orderRefund.setBuyerDesc("拼团失败：系统自动退款");
            orderRefund.setReturnMoneySts(ReturnMoneyStsType.SUCCESS.value());
            orderRefund.setSellerMsg("拼团失败：系统自动退款");
            orderRefund.setApplyTime(new Date());
            orderRefund.setHandelTime(new Date());
            orderRefund.setUpdateTime(new Date());
            orderRefundList.add(orderRefund);

            // 生成退款数据
            OrderRefundDto orderRefundDto = mapperFacade.map(orderRefund, OrderRefundDto.class);
            orderRefundDto.setOrderNumber(refundOrder.getOrderNumber());
            orderRefundDto.setOrderAmount(refundOrder.getActualTotal());
            orderRefundDto.setSettlementId(refundOrder.getSettlementId());
            orderRefundDto.setOrderPayNo(refundOrder.getOrderPayNo());
            orderRefundDto.setDistributionTotalAmount(0.0);
            orderRefundDtoList.add(orderRefundDto);
        }

        if (orderRefundList.size() > 0) {
            orderRefundService.saveBatch(orderRefundList);
        }
        return orderRefundDtoList;
    }

    /**
     * 如果未成团，有机器人可以成团，不需要进行退款的操作
     * @param nowDate 当前时间
     * @param groupTeam 团购团队
     * @param groupProdList 团购商品列表
     * @param robot 参团机器人
     * @param changeStatusOrderList 需要改变状态的订单列表
     * @param returnStockOrders 需要还原库存的订单列表
     */
    private void handleWaitingGroupOrder(Date nowDate, GroupTeam groupTeam, List<GroupProd> groupProdList, List<GroupOrder> robot, List<Order> changeStatusOrderList, List<Order> returnStockOrders) {
        // 更新活动物品成团订单数/已成团人数
        GroupProd groupProd = groupProdService.getById(groupTeam.getGroupProdId());
        groupProd.setGroupOrderCount(groupProd.getGroupNumberCount() + groupTeam.getJoinNum());
        groupProd.setGroupNumberCount(groupOrderMapper.getHadGroupNumberCount(groupProd.getGroupActivityId(), groupProd.getGroupProdId()));
        groupProdList.add(groupProd);

        // 模拟参团操作（添加机器人）
        for (int i = 0; i < groupTeam.getGroupNumber() - groupTeam.getJoinNum(); i++) {
            GroupOrder groupOrder = new GroupOrder();
            groupOrder.setShopId(groupTeam.getShopId());
            groupOrder.setGroupTeamId(groupTeam.getGroupTeamId());
            groupOrder.setUserId("0");
            groupOrder.setIdentityType(0);
            groupOrder.setStatus(1);
            groupOrder.setCreateTime(nowDate);
            robot.add(groupOrder);
        }
        // 更新拼团团队订单
        groupTeam.setJoinNum(groupTeam.getGroupNumber());
        groupTeam.setStatus(TeamStatusEnum.SUCCESS.value());

        // 更新所有的已支付订单状态
        List<Order> teamOrderList = groupTeamMapper.getOrders(groupTeam.getGroupTeamId(),1);
        for (Order order : teamOrderList) {
            order.setStatus(OrderStatus.PADYED.value());
            changeStatusOrderList.add(order);
        }
        // 获取未支付要取消的订单
        List<Order> unPayOrderList = groupTeamMapper.getOrders(groupTeam.getGroupTeamId(),0);
        if(CollectionUtils.isNotEmpty(unPayOrderList)){
            // 需要还原库存的订单
            returnStockOrders.addAll(unPayOrderList);
            for (Order order : unPayOrderList) {
                order.setStatus(OrderStatus.CLOSE.value());
                order.setUpdateTime(nowDate);
                order.setCancelTime(nowDate);
                changeStatusOrderList.add(order);
            }
        }
    }
    /**
     * 如果在拼团中订单且没有模拟成团则需要退款
     * @param groupTeam 团购团队
     * @param changeStatusOrderList 需要改变状态的订单列表
     */
    private void handleRefundGroupOrder(GroupTeam groupTeam, List<Order> changeStatusOrderList) {
        // 更新拼团团队订单
        groupTeam.setStatus(TeamStatusEnum.FAIL.value());

        // 查询未成团的订单列表
        List<GroupRefundOrder> groupRefundOrders = groupTeamMapper.getJoinNotGroupTeamOrder(groupTeam.getGroupTeamId());
        // 需要退款订单
        List<GroupRefundOrder> needRefundOrder = new ArrayList<>();
        // 无需退款订单
        List<GroupOrder> noNeedGroupOrder = new ArrayList<>();

        for (GroupRefundOrder groupRefundOrder : groupRefundOrders) {
            if (groupRefundOrder.getPayStatus() == 1) {
                needRefundOrder.add(groupRefundOrder);
            } else {
                GroupOrder groupOrder = new GroupOrder();
                groupOrder.setGroupOrderId(groupRefundOrder.getGroupOrderId());
                groupOrder.setStatus(GroupOrderStatusEnum.FAIL.value());
                noNeedGroupOrder.add(groupOrder);
            }

            // 修改订单退款状态
            Order order = new Order();
            order.setOrderId(groupRefundOrder.getOrderId());
            order.setStatus(OrderStatus.CLOSE.value());
            order.setCancelTime(new Date());
            order.setUpdateTime(new Date());
            order.setRefundStatus(RefundStatusEnum.SUCCEED.value());
            changeStatusOrderList.add(order);
        }

        // 将订单变为失效状态
        if (CollectionUtil.isNotEmpty(noNeedGroupOrder)) {
            groupOrderService.updateBatchById(noNeedGroupOrder);
        }


        List<OrderRefundDto> orderRefundDtos = saveRefundOrderAndGetOrderRefundDtoByGroupTeamId(needRefundOrder);
        // 真正的退款操作
        orderRefundService.systemAutoRefundBatch(orderRefundDtos);

        // 消息推送-拼团失败
        List<String> orderNumbers = new ArrayList<>();
        orderRefundDtos.forEach(orderRefundDto ->  orderNumbers.add(orderRefundDto.getOrderNumber()));
        List<Order> orderList = orderService.list(new LambdaQueryWrapper<Order>().in(Order::getOrderNumber, orderNumbers));
        for (Order order : orderList) {
            notifyTemplateService.sendNotifyOfGroupStart(order, SendType.GROUP_FAIL);
        }
    }

}
